#include <omp.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define BL char

#define MAX_LOG_SIZE 10000
#define MAX_MESSAGE_SIZE 10

#define WRITE_LOG(beg, end, str) \
do {\
	size_t i = omp_get_thread_num(); \
	log.log_array[i][log.cur_size[i]] = beg; \
	strcpy(log.messages[i][log.cur_size[i]++], str);\
	log.log_array[i][log.cur_size[i]] = end;\
	strcpy(log.messages[i][log.cur_size[i]++], str);\
} while(0)

typedef struct {
	double **log_array;
	char ***messages;
	size_t *cur_size;
	size_t num_threads;
} logger_t;

logger_t log;

// Safe Bool SRSW
struct SBSRSWRegister { BL value; };
void InitLogArray(size_t num_threads) {
	log.num_threads = num_threads;
	log.log_array = calloc(num_threads, sizeof(*log.log_array));
	assert(log.log_array);
	log.cur_size = calloc(num_threads, sizeof(*log.cur_size));
	assert(log.cur_size);
	log.messages = calloc(num_threads, sizeof(*log.messages));
	assert(log.messages);
	size_t i = 0;
	for (; i < num_threads; ++i) {
		log.log_array[i] = calloc(MAX_LOG_SIZE,
		                          sizeof(*(log.log_array[i])));
		assert(log.log_array[i]);
		log.messages[i] = calloc(MAX_LOG_SIZE,
					 sizeof(*(log.messages[i])));
		assert(log.messages[i]);
		size_t j = 0;
		for (; j < MAX_LOG_SIZE; ++j) {
			log.messages[i][j] = calloc(MAX_MESSAGE_SIZE, 1);
			assert(log.messages[i][j]);
		}
	}
}

void FinalizeLogArray() {
	size_t i = 0;
	for (; i < log.num_threads; ++i) {
		size_t j = 0;
		for (; j < log.cur_size[i] ; ++j) {
			printf("\n%d\t%f\t[%s]", i, log.log_array[i][j], 
			       log.messages[i][j]);
		}
		printf("\tout");
		
	}	

	for (i = 0; i < log.num_threads; ++i) {
		size_t j = 0;
		for (; j < MAX_LOG_SIZE; ++j) 
			free(log.messages[i][j]);
		free(log.log_array[i]);
		free(log.messages[i]);
	}

	free(log.log_array);
	free(log.cur_size);
}

BL read_SBSRSWRegister(struct SBSRSWRegister *reg) { 
	BL temp = reg->value;
	return temp; 
}

void write_SBSRSWRegister(struct SBSRSWRegister *reg, BL val) {
	reg->value = val;
}

// Safe Bool MRSW
struct SBMRSWRegister {	struct SBSRSWRegister *values; int size; };
                               	
void init_SBMRSWRegister(struct SBMRSWRegister *reg, int N) { 
	reg->values = (struct SBSRSWRegister*)malloc(N*sizeof(struct SBSRSWRegister)); 
	memset(reg->values, 0, N);
	reg->size = N; 
}

void write_SBMRSWRegister(struct SBMRSWRegister *reg, BL val) { 
	double beg = omp_get_wtime();
	size_t i;
	for (i = 0; i < reg->size; i++) {
		write_SBSRSWRegister(reg->values + i, val); 	
	} 
	double end = omp_get_wtime();

	WRITE_LOG(beg, end, "W");
}

BL read_SBMRSWRegister(struct SBMRSWRegister *reg) {
	double beg = omp_get_wtime();
	int tid = omp_get_thread_num(); 
	BL temp = read_SBSRSWRegister(reg->values + tid);
	double end = omp_get_wtime();

	WRITE_LOG(beg, end, "R");

	return temp;
}
